<template>
  <div class="window">
    <div class="btns">
      <el-form :inline="true">
        <el-form-item>
          <el-button @click="newBpmn">
            <el-icon>
              <CirclePlus />
            </el-icon>
            新建
          </el-button>
        </el-form-item>
        <el-form-item>
          <el-button @click="saveXml">
            <el-icon>
              <Folder />
            </el-icon>
            保存
          </el-button>
        </el-form-item>
        <el-form-item>
          <el-button @click="downbpmn">
            <el-icon>
              <Download />
            </el-icon>
            导出BPMN格式
          </el-button>
        </el-form-item>
        <el-form-item>
          <el-button @click="downsvg">
            <el-icon>
              <Download />
            </el-icon>
            导出SVG格式
          </el-button>
        </el-form-item>
        <el-form-item>
          <el-upload :show-file-list="false" action="" accept=".bpmn" :http-request="upbpmn">
            <el-button>
              <el-icon>
                <Upload />
              </el-icon>
              导入BPMN格式
            </el-button>
          </el-upload>
        </el-form-item>
        <el-form-item>
          <el-button-group>
            <el-button @click="revoke">撤销</el-button>
            <el-button @click="recovery">恢复</el-button>
          </el-button-group>
        </el-form-item>
        <el-form-item>
          <el-button-group>
            <el-button @click="amplification(0.1)">放大</el-button>
            <el-button @click="amplification(-0.1)">缩小</el-button>
            <el-button @click="amplification(0)">还原</el-button>
          </el-button-group>
        </el-form-item>
      </el-form>
    </div>
    <div id="containers">
      <div id="canvas" ref="canvas"></div>
      <div class="panelbox">
        <div id="js-properties-panel" class="panel"></div>
      </div>
    </div>
  </div>
</template>
<script setup>
// 引入相关的依赖
import 'bpmn-js/dist/assets/diagram-js.css';
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css';
import BpmnModeler from "bpmn-js/lib/Modeler";

import customTranslate from '../common/customTranslate/customTranslate';

// 右侧属性栏
import 'bpmn-js-properties-panel/dist/assets/properties-panel.css'
import { BpmnPropertiesPanelModule, BpmnPropertiesProviderModule, CamundaPlatformPropertiesProviderModule } from "bpmn-js-properties-panel";
import camundaModdleDescriptor from "camunda-bpmn-moddle/resources/camunda";
import { onMounted, reactive, ref } from "vue";

const canvas = ref(null)
const state = reactive({
  // bpmn建模器
  bpmnModeler: null,
  container: null,
  canvas: null,
  scale: 1
})

onMounted(() => {
  init()
})

// 流程引擎初始化
const init = () => {
  // 获取到属性ref为“canvas”的dom节点
  state.canvas = document.getElementById('canvas');
  const customTranslateModule = {
    translate: ["value", customTranslate],
  };
  // 建模
  state.bpmnModeler = new BpmnModeler({
    container: state.canvas,
    //添加控制板
    propertiesPanel: {
      parent: "#js-properties-panel",
    },
    additionalModules: [
      // 右边的属性栏
      BpmnPropertiesPanelModule,
      BpmnPropertiesProviderModule,
      CamundaPlatformPropertiesProviderModule,

      // 汉化
      customTranslateModule,
    ],
    moddleExtensions: {
      camunda: camundaModdleDescriptor,
    },
  });

  newBpmn()
}

// 创建流程
const createNewDiagram = (bpmn) => {
  state.bpmnModeler.importXML(bpmn, (err) => {
    if (err) {
      console.error(err)
    } else {
      // 这里是成功之后的回调, 可以在这里做一系列事情
      console.log("成功导入模型");
    }
  });
}

// 新建
const newBpmn = () => {
  state.bpmnModeler.createDiagram().then(res => {
    console.log(res, "新建")
    state.scale = 1
    state.bpmnModeler.get('canvas').zoom('fit-viewport');
  })
}

// 导出下载
const initdownload = ({ name = "diagram.bpmn", data }) => {
  let encodedData = encodeURIComponent(data);

  if (data) {
    // 创建A标签
    let downloadLink = document.createElement('a')
    // 将数据给到链接
    downloadLink.href = "data:application/bpmn20-xml;charset=UTF-8," + encodedData;
    // 设置文件名
    downloadLink.download = name;
    // 触发点击事件开始下载
    downloadLink.click();
  }
}

// 导出文件名称
const getFilename = (xml) => {
  let start = xml.indexOf("process");
  let filename = xml.substr(start, xml.indexOf(">"));
  filename = filename.substr(filename.indexOf("id") + 4);
  filename = filename.substr(0, filename.indexOf('"'));
  return filename;
}

// 导出BPMN格式
const downbpmn = () => {
  state.bpmnModeler.saveXML({ format: true }, (err, xml) => {
    if (!err) {
      // 获取文件名
      let name = `${getFilename(xml)}.xml`;
      // 将文件名以及数据交给下载方法
      initdownload({ name: name, data: xml });
    }
  })
}

// 导出SVG格式
const downsvg = () => {
  state.bpmnModeler.saveXML({ format: true }, (err, xml) => {
    if (!err) {
      // 获取文件名
      let name = `${getFilename(xml)}.svg`;

      // 从建模器画布中提取svg图形标签
      let context = "";
      let djsGroupAll = canvas.value.querySelectorAll(".djs-group");
      for (let item of djsGroupAll) {
        context += item.innerHTML;
      }
      // 获取svg的基本数据，长宽高
      let viewport = canvas.value.querySelector(".viewport").getBBox();

      // 将标签和数据拼接成一个完整正常的svg图形
      let svg = `<svg
                          xmlns="http://www.w3.org/2000/svg"
                          xmlns:xlink="http://www.w3.org/1999/xlink"
                          width="${viewport.width}"
                          height="${viewport.height}"
                          viewBox="${viewport.x} ${viewport.y} ${viewport.width} ${viewport.height}"
                          version="1.1"
                          >
                          ${context}
                        </svg>`;
      // 将文件名以及数据交给下载方法
      initdownload({ name: name, data: svg });
    }
  })
}

// 上传BPMN格式
const upbpmn = (faile) => {
  console.log(faile, "上传的文件")
  openBpmn(faile.file)
}

const openBpmn = (file) => {
  let reader = new FileReader();
  // 读取File对象中的文本信息，编码格式为UTF-8
  reader.readAsText(file, "utf-8");
  reader.onload = () => {
    // 读取完毕后将文本信息导入到Bpmn建模器
    createNewDiagram(reader.result);
  };
  return false;
}

// 撤销
const revoke = () => {
  state.bpmnModeler.get("commandStack").undo();
}

// 恢复
const recovery = () => {
  state.bpmnModeler.get("commandStack").redo();
}

// 放大、缩小、还原
const amplification = (val) => {
  let newScale = !val ? 1.0 : state.scale + val;
  state.bpmnModeler.get("canvas").zoom(newScale);
  state.scale = newScale;
}


// 保存
const saveXml = () => {
  state.bpmnModeler.saveXML({ format: true }).then(res => {
    console.log(res.xml, "保存");
  }, err => {
    console.log(err, "保存出错")
  })
}

</script>

<style lang="scss" scoped>

.window {
  width: 100%;
  height: 100%;

  :deep(.bjs-powered-by) {
    display: none !important;
  }
}

#containers {
  position: relative;
  background-color: #ffffff;
  width: 100%;
  height: calc(100% - 52px);

  #canvas {
    width: 100%;
    height: 100%;
  }

  .panelbox {
    width: 300px;
    height: 100%;
    position: absolute;
    right: 0;
    top: 0;
    z-index: 999;
    overflow: auto;
  }

  .panel {
    width: 300px;
    height: 100%;
  }


}

.btns {
  // position: absolute;
  // top: 0;
  // left: 0;
}
</style>